package com.anji.plus.gaea.security.security.handler;

import com.alibaba.fastjson.JSONObject;
import com.anji.plus.gaea.GaeaProperties;
import com.anji.plus.gaea.bean.ResponseBean;
import com.anji.plus.gaea.cache.CacheHelper;
import com.anji.plus.gaea.constant.Enabled;
import com.anji.plus.gaea.constant.GaeaConstant;
import com.anji.plus.gaea.constant.GaeaKeyConstant;
import com.anji.plus.gaea.event.LoginEvent;
import com.anji.plus.gaea.security.cache.CacheKeyEnum;
import com.anji.plus.gaea.security.code.UserResponseCode;
import com.anji.plus.gaea.security.i18.GaeaMessageSourceAccessor;
import com.anji.plus.gaea.security.security.extension.UserDetailsServiceHelper;
import com.anji.plus.gaea.utils.ApplicationContextUtils;
import com.anji.plus.gaea.utils.JwtBean;
import com.anji.plus.gaea.security.i18.GaeaSecurityMessageSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.util.CollectionUtils;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 登录成功
 * @author lr
 * @since 2021-01-27
 */
public class GaeaLoginSuccessHandler implements AuthenticationSuccessHandler {

    @Autowired
    private CacheHelper cacheHelper;

    @Autowired
    private JwtBean jwtBean;

    @Autowired
    private GaeaProperties gaeaProperties;

    @Autowired
    private UserDetailsServiceHelper userDetailsServiceHelper;

    private GaeaMessageSourceAccessor messages = GaeaSecurityMessageSource.getAccessor();

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        response.setCharacterEncoding(GaeaConstant.CHARSET_UTF8);
        response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
        String code = UserResponseCode.USER_LOGIN_SUCCESS;
        ResponseBean.Builder builder = ResponseBean.builder();
        String username = authentication.getName();

        List<String> userOrgCodes = userDetailsServiceHelper.getUserOrgCodes(username);
        //没有任何组织时
        if (CollectionUtils.isEmpty(userOrgCodes)) {
            String noRole = UserResponseCode.USER_HAS_NO_ROLE;
            String noRoleMessage = messages.getMessage(noRole, noRole);
            response.getWriter().print(JSONObject.toJSONString(ResponseBean.builder().code(noRole).message(noRoleMessage).build()));
        }

        //该用户独有的私钥
        String token = jwtBean.createToken(username);

        //保存登录token,并默认两个小时
        cacheHelper.stringSetExpire(GaeaKeyConstant.USER_LOGIN_TOKEN + token, Enabled.YES.getValue() + "",
                gaeaProperties.getSecurity().getJwtTokenTimeout(), TimeUnit.SECONDS);

        //删除错误次数
        cacheHelper.delete(CacheKeyEnum.USER_PASSWORD_ERROR_NUMBER.getKey() + username);

        //保存权限并清空旧的权限
        String[] authorities =
                authentication.getAuthorities()
                        .stream()
                        .map(GrantedAuthority::getAuthority)
                        .collect(Collectors.toList())
                        .toArray(new String[]{});

        cacheHelper.setAdd(CacheKeyEnum.USER_AUTHORITIES.getKey() + username, authorities, true);

        Map<String,String> data = new HashMap(2);
        data.put("token", token);
        data.put("orgCode", userOrgCodes.get(0));
        ResponseBean responseBean = builder.code(UserResponseCode.SUCCESS).data(data).build();
        responseBean.setMessage(messages.getMessage(code,code));
        response.getWriter().print( JSONObject.toJSONString(responseBean));
        //发布登录事件
        ApplicationContextUtils.publishEvent(new LoginEvent(username));
    }
}
